package com.shuzhi.stationarysource.modules.quartz.config;

import org.quartz.Scheduler;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

/**
 * @ClassName QuartzConfig
 * @Description 定时任务配置  如何为Quartz的Job自动装配Spring容器Bean
 * @Author 孙峰
 * @Date 2020/3/10 9:35
 * @Version 1.0
 */
@Configuration
public class QuartzConfig {


    /**
     * 解决Job中注入Spring Bean为null的问题
     * 自定义的工厂类 QuartzJobFactory 只需要继承 AdaptableJobFactory ，
     * 通过调用父类 AdaptableJobFactory 的方法来实现对Job的实例化，在Job实例化完以后，
     * 再调用自身方法为创建好的Job实例进行属性自动装配并将其纳入到Spring容器的管理之中。
     */
    @Component("quartzJobFactory")
    public static class QuartzJobFactory extends AdaptableJobFactory {
        // 需要使用这个BeanFactory对Quartz创建好Job实例进行后续处理，属于Spring的技术范畴.
        private final AutowireCapableBeanFactory capableBeanFactory;

        public QuartzJobFactory(AutowireCapableBeanFactory capableBeanFactory) {
            this.capableBeanFactory = capableBeanFactory;
        }
        // 首先，调用父类的方法创建好Quartz所需的Job实例
        @Override
        protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {

            //调用父类的方法
            Object jobInstance = super.createJobInstance(bundle);
            // 然后，使用BeanFactory为创建好的Job实例进行属性自动装配并将其纳入到Spring容器的管理之中，属于Spring的技术范畴.
            capableBeanFactory.autowireBean(jobInstance);
            return jobInstance;
        }
    }



    /**
     * 注入scheduler到spring
     * @param quartzJobFactory /
     * @return Scheduler
     * @throws Exception /
     * @Description SchedulerFactoryBean 使用 AdaptableJobFactory 对Job对象进行实例化，如果未指定则SchedulerFactoryBean
     * 会自动创建一个，在这里如果我们能够将 SchedulerFactoryBean 的 jobFactory 指定为我们自定义的工厂实例的话，
     * 我们就能够有机会在Job实例化完成之后对其进行处理，并将其纳入到Spring容器的管理之中。

     */
    @Bean(name = "scheduler")
    public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception {
        SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
        factoryBean.setJobFactory(quartzJobFactory);
        factoryBean.afterPropertiesSet();
        Scheduler scheduler=factoryBean.getScheduler();
        scheduler.start();
        return scheduler;
    }
}
